package com.peng.order.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.peng.order.constant.Constant;
import com.peng.order.dao.repository.OrderRepository;
import com.peng.order.feign.DeviceClient;
import com.peng.order.feign.UserClient;
import com.peng.order.dao.mapper.OrderSuccessMapper;
import com.peng.order.mqtt.MqttProducer;
import com.peng.order.pojo.dto.*;
import com.peng.order.pojo.po.ChargingBillSuccessPO;
import com.peng.order.service.OrderService;
import com.peng.pojo.StationInfoVO;
import com.peng.pojo.UserInfoVO;
import com.peng.pojo.param.GunStatusUpdateParam;
import com.peng.web.JsonResult;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.util.List;
import java.util.Random;

/**
 * 订单服务业务层实现类
 * @author： Peng
 * @date： 2024/6/20
 * @version: 1.0
 */
@Service
@Slf4j
public class OrderServiceImpl implements OrderService {
    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private UserClient userClient;
    @Autowired
    private DeviceClient deviceClient;
    @Autowired
    private MqttProducer mqttProducer;
    @Autowired
    private MqttClient mqttClient;
    @Autowired
    private OrderSuccessMapper orderSuccessMapper;
    @Autowired
    private OrderRepository orderRepository;


    @Override
    public String createOrder(OrderAddParam orderAddParam) {
        /*
         * 1.扫码
         * 2.判断余额
         * 3.创建订单
         * 4.给设备下发指令 开始充电
         */
        log.info("执行订单服务创建订单方法");
        //生成订单号
        String orderNo = buildOrderNo();
        //根据枪id获取运营商信息和充电站信息
        StationInfoDto stationInfo = getStationInfo(orderAddParam.getGunId());
        log.debug("获取运营商和场站信息-入参:{},出参:{}",orderAddParam.getGunId(),stationInfo);
        //根据用户id获取用户车辆信息
        CarInfoDto carInfo = getCarInfo(orderAddParam.getUserId());
        log.debug("获取用户车辆信息-入参:{},出参:{}",orderAddParam.getUserId(),carInfo);
        //根据枪id修改枪状态为2-已使用
        Boolean success = updateGunStatus(orderAddParam.getGunId(), Constant.GUN_STATS_BUSY);
        //校验修改枪状态是否成功
        if (!success){
            log.warn("修改枪状态失败,枪id:{},状态:{}",orderAddParam.getGunId(),Constant.GUN_STATS_BUSY);
        }
        //向充电桩发送开始充电指令
        //发送开始充电指令
        try {
            startCharging(orderAddParam.getGunId(), orderAddParam.getPileId(), orderNo);
        } catch (MqttException e) {
            throw new RuntimeException(e);
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }
        //保存成功订单数据
//        testSaveOrderInfo();
        return orderNo;
    }

    private void testSaveOrderInfo() {
        ChargingBillSuccessPO orderPO = new ChargingBillSuccessPO();
        orderPO.setBillId("10000_53_1719541532504");
        //影响行数
        int insert = orderSuccessMapper.insert(orderPO);
        System.out.println(insert);
        //R read
        ChargingBillSuccessPO chargingBillSuccessPO = orderSuccessMapper.selectById(1);
        System.out.println(chargingBillSuccessPO);

        QueryWrapper wrapper = new QueryWrapper();
        wrapper.eq("bill_id", "10000_53_1719541532504");

        List list = orderSuccessMapper.selectList(wrapper);
        System.out.println(list);
        orderSuccessMapper.deleteById(1);
    }


    @Override
    public void saveSuccessOrder(DeviceResultParam deviceResultParam) {
        ChargingBillSuccessPO successPO = new ChargingBillSuccessPO();
        successPO.setBillId(deviceResultParam.getOrderNo());
        orderRepository.saveSuccessOrder(successPO);
    }

    @Override
    public void saveFailOrder() {

    }

    @Override
    public List<ChargingBillSuccessPO> orderList(Integer userId) {
        List<ChargingBillSuccessPO> chargingBillSuccessPOS =
                orderRepository.orderList(userId);
        return chargingBillSuccessPOS;
    }

    /**
     * 异步下发充电指令给充电桩
     * @param gunId 枪id
     * @param pileId 充电桩id
     * @param orderNo 订单号
     */
    private void startCharging(Integer gunId, Integer pileId, String orderNo) throws MqttException, JsonProcessingException {
        ChargingDto chargingDto = new ChargingDto();
        chargingDto.setGunId(gunId);
        chargingDto.setPileId(pileId);
        chargingDto.setOrderNo(orderNo);
        chargingDto.setMsg(Constant.START_CHARGING);
        log.debug("向充电桩发送开始充电指令：{}",chargingDto);
        mqttProducer.send(chargingDto);
    }

    /**
     * 更新枪的状态
     * @param gunId
     * @param status
     * @return
     */
    private Boolean updateGunStatus(Integer gunId, Integer status) {
        GunStatusUpdateParam param = new GunStatusUpdateParam();
        param.setId(gunId);
        param.setStatus(status);
        JsonResult<Boolean> jsonResult = deviceClient.updateStationStatus(param);
        if (jsonResult != null) {
            return jsonResult.getData();
        }
        return false;
    }




    /**
     * 通过feign的方式调用用户服务
     * @param userId
     * @return
     */
    private CarInfoDto getCarInfoByFeign(Long userId){
        JsonResult<UserInfoVO> userInfo = userClient.getUserInfo(userId);
        log.debug("通过feign调用用户接口获取用户信息-入参:{},出参:{}",userId,userInfo);
        if (userInfo != null) {
            UserInfoVO data = userInfo.getData();
            if (data != null) {
                CarInfoDto carInfoDto = new CarInfoDto();
                BeanUtils.copyProperties(data, carInfoDto);
                return carInfoDto;
            }
        }
        return null;
    }



    /**
     * 通过用户id获取用户绑定的车辆信息
     * 先假定一个用户只能绑定一辆车 充电的时候就是用户绑定的那辆唯一的车
     * 如果后续功能迭代 充电的时候由用户选择给哪辆车充电, 车的id可以通过入参的方式传入
     * @param userId
     * @return
     */
    private CarInfoDto getCarInfo(Long userId) {
        return getCarInfoByFeign(userId);
    }

    /**
     * 通过RestTemplate 来调用用户服务
     * @param userId
     * @return
     */
    private CarInfoDto getCarInfoByRestTemplate(Integer userId) {
        String url = choseUrl();
        log.debug("通过restTemplate调用用户接口获取用户信息-获取url:{}",url);
        //String url = "http://localhost:8083/user/info/"+userId;
        log.debug("通过restTemplate调用用户接口获取用户信息-入参:{}",userId);
        ParameterizedTypeReference<JsonResult<UserInfoVO>> reposeBody =
                new ParameterizedTypeReference<JsonResult<UserInfoVO>>() {
                };
        ResponseEntity<JsonResult<UserInfoVO>> entity =
                restTemplate.
                        exchange(url,
                                HttpMethod.GET,
                                null,
                                reposeBody,
                                userId);
        log.debug("通过restTemplate调用用户接口获取用户信息-入参:{},出参:{}",userId,entity);

        if(entity != null) {
            HttpStatus statusCode = entity.getStatusCode();
            if (HttpStatus.OK == statusCode) {
                JsonResult<UserInfoVO> body = entity.getBody();
                UserInfoVO data = body.getData();
                log.debug("通过restTemplate调用用户接口获取用户信息-入参:{},body:{}",userId,body);
                CarInfoDto carInfoDto = new CarInfoDto();
                Integer carId = data.getCarId();
                carInfoDto.setCarId(carId); //如果参数少可以同手动设置
                BeanUtils.copyProperties(data,carInfoDto);
                return carInfoDto;
            }
        }
/*
        CarInfoDto carInfoDto = new CarInfoDto();
        carInfoDto.setCarId(15);
        return carInfoDto;*/
        return null;
    }

    /**
     * 选择不同的用户服务器url
     * @return
     */
    private static String choseUrl() {
//        List<String> servers = nocos.getUrl("userService")
//        random 选中一个
//        feign
        String url = "http://localhost:8083/user/info/{userId}";
        String url1 = "http://localhost:8084/user/info/{userId}";
        String url2 = "http://localhost:8085/user/info/{userId}";

        //模拟随机算法负载均衡
        String[] urls = new String[3];
        urls[0] = url;
        urls[1] = url1;
        urls[2] = url2;
        Random random = new Random();
        int index = random.nextInt(urls.length);
        System.out.println("url:"+urls[index]);
        return url;
    }



    /**
     * 通过枪id获取运营商信息和充电站信息
     * @param gunId
     * @return StationInfoDto
     */
    private StationInfoDto getStationInfo(Integer gunId) {
        JsonResult<StationInfoVO> stationInfo = deviceClient.getStationInfo(gunId);
        if (stationInfo != null) {
            StationInfoVO data = stationInfo.getData();
            if (data != null) {
                StationInfoDto dto = new StationInfoDto();
                BeanUtils.copyProperties(data,dto);
                return dto;
            }
        }
        return null;
    }

    /**
     * 生成订单号
     * 固定开始的 10000 + _ + 随机数 + _ + 时间戳
     * @return String orderNo
     */
    private static String buildOrderNo() {
        Random random = new Random();
        String orderNo = "10000_"+System.currentTimeMillis()+"_"+ random.nextInt(100);
        return orderNo;
    }
}
